<?php

namespace Home\Lib;

/**
 * 一些常用函数.
 *
 * @author YangZi <purocean@outlook.com>
 *
 * @link https://github.com/purocean/
 *
 * @copyright 2013-2015
 */
class YCom
{
    /**
     * 解析字符串到数组.
     *
     * @param string $str       要解析的字符串，如 a=1&b=2
     * @param string $glue      粘和剂, 如上面的 &
     * @param string $separator 分隔符， 如上面的 =
     * @param bool   $trim      是否去除键的空白
     *
     * @return array 如 ['a' => '1', 'b' => '2']
     */
    public static function parseStr($str, $glue = '&', $separator = '=', $trim = false)
    {
        $return = array();
        $arr = explode($glue, $str);
        foreach ($arr as $one) {
            $arrTmp = explode($separator, $one, 2);
            $key = self::issetor($arrTmp[0]);
            $val = self::issetor($arrTmp[1]);
            if ($trim) {
                $key = trim($key);
            }

            $return[$key] = $val;
        }

        return $return;
    }

    /**
     * 获取一个可能未定义的变量.
     *
     * @param mixed &$var    一个变量，可能未设置
     * @param mixed $default 如果没有被设置默认值
     *
     * @return mixed 值
     */
    public static function issetor(&$var, $default = null)
    {
        return !isset($var) ? $default  : $var;
    }

    /**
     * HTML 转义 防止 XSS.
     *
     * @param string $str 字符串
     *
     * @return string 转义后的字符串
     */
    public static function html($str)
    {
        return htmlspecialchars($str, ENT_QUOTES);
    }

    /**
     * 3des 加密.
     *
     * @param string $str 要加密的字符串
     * @param string $key 加密key
     *
     * @return string 加密后的字符串
     */
    public static function encrypt($str, $key)
    {
        $size = mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($size, MCRYPT_RAND);
        $encdata = mcrypt_ecb(MCRYPT_3DES, $key, $str, MCRYPT_ENCRYPT, $iv);

        return base64_encode($encdata);
    }

    /**
     * 3des 解密.
     *
     * @param string $str 要解密的字符串
     * @param string $key 解密key
     *
     * @return string 解密后的字符串
     */
    public static function decrypt($str, $key)
    {
        $size = mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($size, MCRYPT_RAND);
        $encdata = base64_decode($str);

        return trim(mcrypt_ecb(MCRYPT_3DES, $key, $encdata, MCRYPT_DECRYPT, $iv));
    }

    /**
     * 检测字符串是否以某个串开头.
     *
     * @param string $haystack 干草堆
     * @param string $needle   针
     *
     * @return bool
     */
    public static function startsWith($haystack, $needle)
    {
        return $needle === '' || strrpos($haystack, $needle, -strlen($haystack)) !== false;
    }

    /**
     * 检测字符串是否以某个串结束.
     *
     * @param string $haystack 干草堆
     * @param string $needle   针
     *
     * @return bool
     */
    public static function endsWith($haystack, $needle)
    {
        return $needle === '' || strpos($haystack, $needle, strlen($haystack) - strlen($needle)) !== false;
    }

    /**
     * 判断某个字符串是否在一个字符串数组中.
     *
     * @param string $key   检测字符串
     * @param array  $strs  字符串数组
     * @param bool   $whole 是否完全匹配
     * @param bool   $case  是否区分大小写
     *
     * @return bool 是否匹配
     */
    public function keyMatch($key, $strs, $whole = false, $case = false)
    {
        $result = false;
        if ($case) {
            $func = 'strpos';
        } else {
            $func = 'stripos';
        }

        foreach ($strs as $str) {
            if ($whole) {
                if ($str == $key) {
                    $result = true;
                    break;
                }
            } else {
                if ($func($key, $str) !== false) {
                    $result = true;
                    break;
                }
            }
        }

        return $result;
    }

    /**
     * 去除 HTML 字符串里的空白.
     *
     * @param string $str 输入字符串
     *
     * @return string 输出处理后的字符串
     */
    public static function clearBlank($str)
    {
        $str = str_replace(' ', '', $str);
        $str = str_replace("\n", '', $str);
        $str = str_replace("\r", '', $str);
        $str = str_replace("\t", '', $str);
        $str = str_ireplace('&nbsp;', '', $str);

        return $str;
    }

    /**
     * 删除URI中某个字段.
     *
     * @param string $url URI
     * @param string $key 键
     *
     * @return string 删除后的结果
     */
    public static function removeUriVar($uri, $key)
    {
        $uri = preg_replace("/(.*)(&{0,1}){$key}=[^&]+?(&)(.*)/i", '$1$2$4', $uri.'&');
        $uri = rtrim($uri, '&');
        $uri = rtrim($uri, '?');

        return $uri;
    }

    /**
     * 获取访问 IP.
     *
     * @return string 用户的IP
     */
    public static function getIp()
    {
        $userip = null;

        if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
            $userip = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
            $userip = getenv('HTTP_X_FORWARDED_FOR');
        } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
            $userip = getenv('REMOTE_ADDR');
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $userip = $_SERVER['REMOTE_ADDR'];
        }

        return $userip;
    }

    /**
     * 获取访问 UA.
     *
     * @return string 用户的UA
     */
    public static function getUa()
    {
        return $_SERVER['HTTP_USER_AGENT'];
    }

    /**
     * sae 记录日志.
     *
     * @param string $msg 日志内容
     */
    public static function saeLog($msg)
    {
        sae_set_display_errors(false); // 关闭信息输出
        sae_debug($msg); // 记录日志
        sae_set_display_errors(true); // 记录日志后再打开信息输出，否则会阻止正常的错误信息的显示
    }

    /**
     * 友好的截取字符串，UTF-8 编码.
     *
     * @param string $sourceStr 原字符串
     * @param int    $cutLength 截取长度
     * @param string $cutLength 超过长度时候添加的后缀
     *
     * @return string 截取后的字符串
     */
    public static function cutStr($sourceStr, $cutLength, $suffix = '...')
    {
        $returnStr = '';
        $offset = 0;
        $count = 0;

        $strLength = strlen($sourceStr); // 字符串的字节数
        while (($count < $cutLength) && ($offset <= $strLength)) {
            $temp_str = substr($sourceStr, $offset, 1);
            $ascnum = Ord($temp_str); // 得到字符串中第$offset位字符的ascii码
            if ($ascnum >= 224) { // 如果ASCII位高与224，
                $returnStr = $returnStr.substr($sourceStr, $offset, 3); // 根据UTF-8编码规范，将3个连续的字符计为单个字符
                $offset += 3; // 实际Byte计为3
                ++$count; // 字串长度计1
            } elseif ($ascnum >= 192) { // 如果ASCII位高与192，
                $returnStr = $returnStr.substr($sourceStr, $offset, 2); // 根据UTF-8编码规范，将2个连续的字符计为单个字符
                $offset += 2; // 实际Byte计为2
                ++$count; // 字串长度计1
            } elseif ($ascnum >= 65 && $ascnum <= 90) { // 如果是大写字母，
                $returnStr = $returnStr.substr($sourceStr, $offset, 1);
                $offset += 1; // 实际的Byte数仍计1个
                ++$count; // 但考虑整体美观，大写字母计成一个高位字符
            } else { //其他情况下，包括小写字母和半角标点符号，
                $returnStr = $returnStr.substr($sourceStr, $offset, 1);
                $offset += 1; // 实际的Byte数计1个
                $count += 0.5; // 小写字母和半角标点等与半个高位字符宽...
            }
        }

        if ($returnStr != $sourceStr) {
            $returnStr = $returnStr.$suffix; // 超过长度时在尾处加上后缀
        }

        return $returnStr;
    }

    /**
     * 获取文件夹列表.
     *
     * @param string $dir 父目录
     * @param int    $max 获取最大数量
     *
     * @return array 文件夹列表
     */
    public static function getDirs($dir, $max = 3000)
    {
        $dirArray = array();
        $handle = opendir($dir);
        if ($handle) {
            $count = 0;
            $dir = rtrim($dir, '/');
            $dir = rtrim($dir, '\\');

            while (false !== ($file = readdir($handle)) && $count < $max) {
                if ($file != '.' && $file != '..' && is_dir($dir.'/'.$file)) {
                    $dirArray[] = $file;
                    ++$count;
                }
            }

            closedir($handle);
        }

        return $dirArray;
    }

    /**
     * 获取文件列表.
     *
     * @param string $dir 父目录
     * @param int    $max 获取最大数量
     *
     * @return array 文件列表
     */
    public static function getFiles($dir, $max = 5000)
    {
        $dirArray = array();
        $handle = opendir($dir);
        if ($handle) {
            $count = 0;
            $dir = rtrim($dir, '/');
            $dir = rtrim($dir, '\\');

            while (false !== ($file = readdir($handle)) && $count < $max) {
                if ($file != '.' && $file != '..' && is_dir($dir.'/'.$file)) {
                    $dirArray[] = $file;
                    ++$count;
                }
            }

            closedir($handle);
        }

        return $dirArray;
    }
}
